package org.cos.generation.util.agorithm;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;

import org.cos.generation.epda.EPDA;
import org.cos.generation.epda.Method;
import org.cos.generation.epda.State;
import org.cos.generation.epda.State.Transition;
import org.cos.generation.util.info.ClassInfo;
import org.cos.generation.util.info.MethodInfo;

public class CustomCallSquelching {

	// 存储自动机的状态
	private State[] states;
	
	// 存储待执行squelch算法的类的信息
	private ClassInfo classInfo;
	
	// 标记已经访问过的状态
	Set<Integer> visitedState;
	
	public void squelch(ClassInfo classInfo) {
		this.classInfo = classInfo;
		EPDA epda = classInfo.getEPDA();
		int stateSize = epda.getStateSize();
		states = new State[stateSize];
		epda.getStates().toArray(states);
		visitedState = new TreeSet<Integer>();
		visitedState.add(0);
		
		List<Transition> transitions = states[0].getTransitions();
		
		List<Transition> removeList = new LinkedList<Transition>();
		// 对每个方法执行squelch算法
		for (Transition trans : transitions) {
			Method method = trans.getMethod();
			MethodInfo methodInfo = classInfo.getMethodInfo(method);
			// 
			if (methodInfo.getSystemFlag() == 0) {
			// 如果该方法的系统调用相关性未确定
				// 对该方法执行squelch算法 
				squelch(methodInfo);
			}
			if (methodInfo.getSystemFlag() == -1) {
			// 如果调用方法是系统调用无关的
				// 将由类初始状态指向它的边加入删除列表
				removeList.add(trans);
			}
		}
		// 删除多余的边
		transitions.removeAll(removeList);
	}
	
	/**
	 * 对指定方法执行squelch
	 * @param methodInfo
	 */
	private void squelch(MethodInfo methodInfo) {
		
		// 获得该方法的起始状态
		int stateIndex = methodInfo.getInitStateIndex();
		// DFS栈
		Stack<Integer> stateStack = new Stack<Integer>();
		// 压入起始状态
		stateStack.push(stateIndex);
		
		while (!stateStack.empty()) {
			
			visitedState.add(stateStack.peek());
			State state = states[stateStack.pop()];
			
			List<Transition> transitions = state.getTransitions();
			
			// 对于所有出边
			for (Transition trans : transitions) {
				
				Method method = trans.getMethod();
				
				if (method == null || !method.isReturn()) {
				// 如果该边是空边或不是返回边
					
					// 从该类的方法表中查找这条边上的调用方法
					MethodInfo tailMethodInfo = 
							classInfo.getMethodInfo(method);
					
					Integer tailState = null;
					
					if (tailMethodInfo != null) {
					// 如果该调用方法在该类中	
						
						int tailReutrnState = tailMethodInfo.getReturnStateIndex();
						Transition tailReturnTrans = null;
						// 在调用方法的返回状态中查找与调用匹配的返回边
						for (Transition returnTrans : states[tailReutrnState].getTransitions()) {
							Method returnMethod = returnTrans.getMethod();
							if (returnMethod != null && returnMethod.equals(trans.getMethod())) {
								tailReturnTrans = returnTrans;
								tailState = returnTrans.getTailIndex();
								break;
							}
						}
						
						if (tailMethodInfo.getSystemFlag() == 0) {
						// 如果调用方法的系统调用相关性未确定
							
							// 对该调用方法执行squelch算法 
							squelch(tailMethodInfo);
						}
						
						if (tailMethodInfo.getSystemFlag() == 1) {
						// 如果调用方法是系统调用相关的
							
							// 将当前方法设置为系统调用相关的
							methodInfo.setSystemRelated();
							return;
						} else if (tailMethodInfo.getSystemFlag() == -1) {
						// 如果调用方法是系统调用无关的
							
							// 删除调用返回边
							states[tailReutrnState].getTransitions().remove(tailReturnTrans);
							// 将调用边置空
							trans.setNull();
							// 目标状态指向原返回后的状态
							trans.setTailIndex(tailState);
						}
					} else {
						// 获得该边的目标状态
						tailState = trans.getTailIndex();
					}
					if (tailState != null && !visitedState.contains(tailState)) {
					// 如果目标状态非空且未访问过
						// 将其压入DFS栈
						stateStack.push(tailState);
					}
				}
			}
		}
		// 如果该方法中没有遇到系统调用相关的边，则将该方法设为系统调用无关的
		methodInfo.setSystemUnrelated();
	}
	
}
